﻿//-----------------------------------------------------------------------
// <copyright>
// This file is subject to the terms and conditions of the Microsoft Public License (MS-PL).
// See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL for more details.
// </copyright>
//----------------------------------------------------------------------- 
using System;
using System.Collections.Generic;
using System.Reflection;

namespace Fulcrum.DispatcherProxies
{
    class DispatcherProxyTargetManager
    {
        SortedDictionary<Type, DispatcherProxyTarget> targets;

        public DispatcherProxyTargetManager()
        {
            this.targets = new SortedDictionary<Type, DispatcherProxyTarget>(new TypeComparer());
        }

        class TypeComparer : IComparer<Type>
        {
            public TypeComparer()
            {
                // nothing
            }

            public int Compare(Type x, Type y)
            {
                return String.Compare(x.FullName, y.FullName, StringComparison.InvariantCultureIgnoreCase);
            }
        }

        public ICollection<DispatcherProxyTarget> Targets
        {
            get
            {
                return this.targets.Values;
            }
        }

        public void AddTargetAssembly(string assemblyName)
        {
            var targetAssembly = Assembly.LoadFrom(assemblyName);
            AddTargetAssembly(targetAssembly);
        }

        void AddTargetAssembly(Assembly targetAssembly)
        {
            foreach(var targetType in targetAssembly.GetTypes())
            {
                ProcessType(targetType);
            }
        }

        void ProcessType(Type targetType)
        {
            if (false == HasTypeBeenProcessed(targetType) && 
                DispatcherProxyGenerationPolicy.IsProxyableType(targetType))
            {
                var baseProxy = FindCreateProxy(targetType.BaseType);

                var target = CreateProxyTarget(targetType, baseProxy);
                this.targets.Add(targetType, target);
            }
        }

        private DispatcherProxyTarget CreateProxyTarget(Type targetType, DispatcherProxyTarget baseProxy)
        {
            var target = new DispatcherProxyTarget(targetType, baseProxy);
            return target;
        }

        private DispatcherProxyTarget FindCreateProxy(Type targetType)
        {
            if( false == HasTypeBeenProcessed(targetType))
            {
                ProcessType(targetType);
            }

            var proxy = FindProxy(targetType);

            return proxy;
        }

        private DispatcherProxyTarget FindProxy(Type targetType)
        {
            DispatcherProxyTarget proxy;

            if(false == this.targets.TryGetValue(targetType, out proxy))
            {
                proxy = null;
            }

            return proxy;
        }

        private bool HasTypeBeenProcessed(Type type)
        {
            return this.targets.ContainsKey(type);
        }

    }
}
